package com.urick.loadbanlance.dubbo;

import cn.hutool.core.util.RandomUtil;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * Design Theories:
 * <a href=""></a>
 * <p>
 * 权重随机算法，随着请求增多，逐渐平均
 *
 * @author uRick 2021/12/13 18:18
 * Email: rickwork@163.com
 * Wechat: yy3076815642
 * QQ: 3076815642
 * @since 1.0
 */
public class RandomLoadBalance extends AbstractLoadBalance {
    @Override
    protected ServerInstance doSelect(List<ServerInstance> instanceList) {
        int length = instanceList.size();
        // Every invoker has the same weight?
        boolean sameWeight = true;
        // the maxWeight of every invokers, the minWeight = 0 or the maxWeight of the last invoker
        int[] weights = new int[length];
        // The sum of weights
        int totalWeight = 0;
        for (int i = 0; i < length; i++) {
            int weight = getWeight(instanceList.get(i));
            // Sum
            totalWeight += weight;
            // save for later use
            weights[i] = totalWeight;
            if (sameWeight && totalWeight != weight * (i + 1)) {
                sameWeight = false;
            }
        }
        if (totalWeight > 0 && !sameWeight) {
            // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
            int offset = ThreadLocalRandom.current().nextInt(totalWeight);
            // Return a invoker based on the random value.
            for (int i = 0; i < length; i++) {
                if (offset < weights[i]) {
                    return instanceList.get(i);
                }
            }
        }
        // If all invokers have the same weight value or totalWeight=0, return evenly.
        return instanceList.get(ThreadLocalRandom.current().nextInt(length));
    }
}
